﻿using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;

namespace FarseerPhysics.SamplesFramework
{
    /// <summary>
    /// 功能键
    /// 游戏逻辑轮询时使用功能键，而不是实际键盘/摇杆
    /// </summary>
    public enum FunctionKeys
    {
        Up,
        Down,
        Left,
        Right,
        Jump,
        Action1,
        Action2,
        Action3,
        Action4,
    }

    /// <summary>
    /// 操作命令优先级，数字越大越优先
    /// </summary>
    public enum CommandPriorities
    {
        Default = 0,
        Dir = 1,
        Action = 2,
        DirAction = 3,
    }

    /// <summary>
    /// Act游戏逻辑使用的输入类
    /// </summary>
    public class ActInput
    {
#region Properties
        private int _queueLength;
        private KeyboardState _currentKeyboardState;
        private KeyboardState _lastKeyboardState;
        private Queue<KeyboardState> _keyboardStateQueue;
        private GamePadState _currentGamePadState;
        private GamePadState _lastGamePadState;
        private Queue<GamePadState> _gamePadStateQueue;
#endregion

        public ActInput()
        {
            _queueLength = 10;
            _currentKeyboardState = new KeyboardState();
            _lastKeyboardState = new KeyboardState();
            _keyboardStateQueue = new Queue<KeyboardState>();
            _currentGamePadState = new GamePadState();
            _lastGamePadState = new GamePadState();
            _gamePadStateQueue = new Queue<GamePadState>();
        }

        public void Update(GameTime gameTime)
        {
            _lastKeyboardState = _currentKeyboardState;
            _currentKeyboardState = Keyboard.GetState();
            _keyboardStateQueue.Enqueue(_currentKeyboardState);
            while (_keyboardStateQueue.Count > _queueLength)
            {
                _keyboardStateQueue.Dequeue();
            }
            _lastGamePadState = _currentGamePadState;
            _currentGamePadState = GamePad.GetState(PlayerIndex.One);
            _gamePadStateQueue.Enqueue(_currentGamePadState);
            while (_gamePadStateQueue.Count > _queueLength)
            {
                _gamePadStateQueue.Dequeue();
            }
        }

        public bool IsKeyDown(KeyMapping mapping, FunctionKeys key)
        {
            return (_currentKeyboardState.IsKeyDown(mapping.GetKey(key)) ||
                _currentGamePadState.IsButtonDown(mapping.GetButton(key)));
        }

        public bool IsKeyUp(KeyMapping mapping, FunctionKeys key)
        {
            return (_currentKeyboardState.IsKeyUp(mapping.GetKey(key)) ||
                _currentGamePadState.IsButtonUp(mapping.GetButton(key)));
        }

        public bool IsKeyTriggered(KeyMapping mapping, FunctionKeys key)
        {
            bool keyTriggered = _currentKeyboardState.IsKeyDown(mapping.GetKey(key)) &&
                _lastKeyboardState.IsKeyUp(mapping.GetKey(key));
            bool buttonTriggered = _currentGamePadState.IsButtonDown(mapping.GetButton(key)) &&
                _lastGamePadState.IsButtonUp(mapping.GetButton(key));
            return (keyTriggered || buttonTriggered);
        }
    }

    /// <summary>
    /// 在ActInput类里面使用的键位映射信息，
    /// 将键盘/摇杆按钮抽象为功能键
    /// </summary>
    public class KeyMapping
    {

        private Dictionary<FunctionKeys, Keys> _function2Keys;

        private Dictionary<FunctionKeys, Buttons> _function2Buttons;

        private KeyMapping()
        {
            _function2Keys = new Dictionary<FunctionKeys, Keys>();
            _function2Buttons = new Dictionary<FunctionKeys, Buttons>();
        }

        public static KeyMapping CreateWSADMapping()
        {
            KeyMapping mapping = new KeyMapping();
            mapping.SetKey(FunctionKeys.Up, Keys.W, Buttons.DPadUp);
            mapping.SetKey(FunctionKeys.Down, Keys.S, Buttons.DPadDown);
            mapping.SetKey(FunctionKeys.Left, Keys.A, Buttons.DPadLeft);
            mapping.SetKey(FunctionKeys.Right, Keys.D, Buttons.DPadRight);
            mapping.SetKey(FunctionKeys.Jump, Keys.Space, Buttons.LeftTrigger);
            mapping.SetKey(FunctionKeys.Action1, Keys.J, Buttons.A);
            mapping.SetKey(FunctionKeys.Action2, Keys.K, Buttons.B);
            mapping.SetKey(FunctionKeys.Action3, Keys.L, Buttons.X);
            mapping.SetKey(FunctionKeys.Action4, Keys.OemSemicolon, Buttons.Y);
            return mapping;
        }

        public Keys GetKey(FunctionKeys function)
        {
            return _function2Keys[function];
        }

        public Buttons GetButton(FunctionKeys function)
        {
            return _function2Buttons[function];
        }

        public void SetKey(FunctionKeys function, Keys key)
        {
            _function2Keys[function] = key;
        }

        public void SetKey(FunctionKeys function, Buttons button)
        {
            _function2Buttons[function] = button;
        }

        public void SetKey(FunctionKeys function, Keys key, Buttons button)
        {
            _function2Keys[function] = key;
            _function2Buttons[function] = button;
        }
    }
}